/*===============================================
Copyright (c): Technology Co.,Ltd. ALL rights reserved. 
                                                                 
  Create by: LIN
      Email:
       Date:
   Filenameo:
Description:
    Version:
Last Change:
                                                                 
=======================================*/
                                                                 
`ifndef MAC_SEQ_ITEM_SV
`define MAC_SEQ_ITEM_SV

class mac_seq_item extends uvm_sequence_item;
    	rand bit	[7:0]  		frame_pre[];
    	rand bit	[7:0] 	 	frame_sfd;
    	rand bit	[5:0][7:0]	destiny_mac_addr;
    	rand bit	[5:0][7:0]	source_mac_addr;
    	rand bit	[15:0]  	frame_type;
	rand byte				pload[];
    	rand bit	[3:0][7:0] 	crc;
	rand int	port_num = -1;
	rand int	data_size = -1;
	rand int 	crc_error;
	rand int	dv_error;
	rand int	delay_time = 0;
	int 		pkt_id = 0;
	real		input_time = 0;
	real		output_time = 0;

	
	constraint mac_cons{
		soft frame_pre.size dist {[1:7] :/ 80, 0 :/ 20};
		foreach	(frame_pre[i])
			frame_pre[i] == 8'h55;
		soft pload.size == data_size;
		soft frame_sfd == 8'hd5;
		soft crc_error inside {0, 1};
		soft dv_error == 0; 
		soft frame_type inside {16'h86dd, 16'h0800, 16'h0806};
		soft port_num inside {[0:3]};
		delay_time inside {[24:100]};
	}
	`uvm_object_utils_begin(mac_seq_item);
		`uvm_field_array_int(frame_pre, UVM_ALL_ON)
		`uvm_field_int(frame_sfd, UVM_ALL_ON)
		`uvm_field_int(destiny_mac_addr, UVM_ALL_ON)
		`uvm_field_int(source_mac_addr, UVM_ALL_ON)
		`uvm_field_int(frame_type, UVM_ALL_ON)
		`uvm_field_array_int(pload, UVM_ALL_ON)
		`uvm_field_int(crc, UVM_ALL_ON)
		`uvm_field_int(port_num, UVM_ALL_ON | UVM_NOPACK)
		`uvm_field_int(crc_error, UVM_ALL_ON | UVM_NOPACK)
		`uvm_field_int(dv_error, UVM_ALL_ON | UVM_NOPACK)
		`uvm_field_int(pkt_id, UVM_ALL_ON | UVM_NOPACK)
		`uvm_field_real(input_time, UVM_ALL_ON | UVM_NOPACK)
		`uvm_field_real(output_time, UVM_ALL_ON | UVM_NOPACK)
		`uvm_field_int(delay_time, UVM_ALL_ON | UVM_NOPACK)

	`uvm_object_utils_end

	extern function new(string name = "mac_seq_item");
	extern function void post_randomize();
	extern function bit[31:0] calc_crc();
	extern function void do_unpack_bytes(byte unsigned queue[$]);
	extern function void my_printf();

	static function bit my_compare(mac_seq_item a, mac_seq_item b);
		return a.input_time < b.input_time;
	endfunction

endclass

function mac_seq_item::new(string name = "mac_seq_item");
	super.new(name);
endfunction

function void mac_seq_item::post_randomize();
	if (crc_error == 0) begin
		crc = calc_crc;
	end
endfunction

function bit[31:0] mac_seq_item::calc_crc();
	bit [31:0] crc = 32'hffffffff;
	byte unsigned data_q[];
	int pack_size;
	pack_size = this.pack_bytes(data_q) / 8;

	for (int i = this.frame_pre.size + 1; i < pack_size - 4; i++) begin
		crc = crc ^ data_q[i];
		for (int j = 8; j > 0; --j) begin
			crc = (crc >> 1) ^ (32'hedb88320 & (-(crc & 1)));
		end
	end
	/*Small to Big endian*/
	crc = crc ^ 32'hffffffff;
	return (crc & 8'hff) << 24 | (crc & 16'hff00) << 8 | (crc & 24'hff0000) >> 8 | (crc >> 24) & 8'hff;
endfunction

function void mac_seq_item::do_unpack_bytes(byte unsigned queue[$]);
	int i = 0;
	int pload_size = 0;
	while (queue[0] == 8'h55) begin
		i++;
		queue.pop_front();
	end
	this.frame_pre = new[i];
	foreach(this.frame_pre[j]) begin
		this.frame_pre[j] = 8'h55;
	end
	this.frame_sfd = queue.pop_front();
	for (i = 5; i >= 0; i--) begin
		this.destiny_mac_addr[i][7:0] = queue.pop_front();  
	end
	for (i = 5; i >= 0; i--) begin
		this.source_mac_addr[i][7:0] = queue.pop_front();  
	end
	this.frame_type[15:8] = queue.pop_front();  
 	this.frame_type[7:0] = queue.pop_front();  
	
	pload_size = queue.size() - 4;
	if (pload_size > 0) begin
		this.pload = new[pload_size];
		foreach (this.pload[j]) begin
			this.pload[j] = queue.pop_front();
		end
	end
	for (i = 3; i >= 0; i--) begin
		this.crc[i][7:0] = queue.pop_front();
	end

endfunction

function void mac_seq_item::my_printf();

	bit [31:0] temp[$];
	string s;
	temp = {>>{pload}};
	$display("\033[32m*****************************************");
	$display($sformatf("[PORT_NUM: %0d]", port_num));
	$display($sformatf("[DES_ADDR: 48'h%12h]", destiny_mac_addr));
	$display($sformatf("[SRC_ADDR: 48'h%12h]", source_mac_addr));
	$display($sformatf("[FRM_TYPE: 16'h%4h]", frame_type));
	$display($sformatf("[PLOAD(BYTE0-BYTE%0d)]:", pload.size() - 1));
	for (int i = 0; i < temp.size(); i++) begin
		if (i % 8 == 0) begin
			s = {s, $sformatf("%6d: ", i * 4)};
		end
		s = {s, $sformatf("%8h", temp[i])};
		if (i % 8 == 7) begin
			s = {s, "\n"};
		end else if (i != temp.size - 1) begin
			s = {s, "_"};
		end
	end
	$display(s);
	$display($sformatf("[CRC_32: 32'h%4h]", crc));
	$display("\033[32m*****************************************\033[0m");

endfunction



`endif
